package com.woniuxy.project.campus.technical.config;

import cn.hutool.json.JSONUtil;
import com.woniuxy.project.campus.AccountOpenFeign;
import com.woniuxy.project.campus.account.model.form.RedisKey;
import com.woniuxy.project.campus.account.model.form.StringKAndVForm;
import com.woniuxy.project.campus.technical.utilTool.MyTool;
import com.woniuxy.project.campus.util.Result;
import lombok.Data;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.springframework.web.socket.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

@Data
public  class WebSocketUtil implements WebSocketHandler {
    private  final Logger LOGGER = LoggerFactory.getLogger(WebSocketUtil.class);

    @Resource
    private MyTool myTool;
    @Resource
    private AccountOpenFeign accountOpenFeign;
    private String userName;
    private WebSocketSession session;

    // 心跳间隔
    private static final long HEARTBEAT_INTERVAL = 30000; // 30秒
    private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();


    /** 固定前缀  */
    private  final String USER_NAME_PREFIX = "user_name_";



    // 静态变量，用来记录当前在线连接数
    private  CopyOnWriteArraySet<WebSocketUtil> webSocketSet = new CopyOnWriteArraySet<>();
    // 静态变量，用来记录客户端会话
    private  ConcurrentHashMap<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
    // 静态变量，用来记录未读消息
    private  ConcurrentHashMap<String, List<String>> unreadMessagesMap = new ConcurrentHashMap<>();




    // 帮助方法，根据会话找到 WebSocketUtil 实例
    private WebSocketUtil findWebSocketUtilBySession(WebSocketSession session) {
        for (WebSocketUtil item : webSocketSet) {
            if (item.getSession().getId().equals(session.getId())) {
                return item;
            }
        }
        return null;
    }




    // 私聊：向指定客户端推送消息
    public synchronized  void privateMessage(SocketMag socketMsg) {
        WebSocketSession receiveUser = sessionMap.get(USER_NAME_PREFIX + socketMsg.getReceiveUser());
        if (receiveUser != null) {
            System.out.println(socketMsg.getSendOutUser() + " 向 " + socketMsg.getReceiveUser() + " 发送了一条消息：" + socketMsg.getMsg());
            try {
                receiveUser.sendMessage(new TextMessage(socketMsg.getSendOutUser() + "：" + socketMsg.getMsg()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(socketMsg.getSendOutUser() + " 私聊的用户 " + socketMsg.getReceiveUser() + " 不在线或者输入的用户名不对");
            unreadMessagesMap.computeIfAbsent(socketMsg.getReceiveUser(), k -> new ArrayList<>())
                    .add(socketMsg.getSendOutUser() + ": " + socketMsg.getMsg());

            WebSocketSession sendOutUser = sessionMap.get(USER_NAME_PREFIX + socketMsg.getSendOutUser());
            if (sendOutUser != null) {
                try {
                    sendOutUser.sendMessage(new TextMessage("系统消息：对方不在线，您的消息已保存，等待对方上线。"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 向特定用户发送通知
    public  synchronized  void sendNotification(String userId, String message) {
        System.out.println("向id为 " + userId + " 发送通知：" + message);
        //通过id 找到姓名
        String userNameByToken = myTool.getUserNameByToken(Integer.valueOf(userId));
        WebSocketSession userSession = sessionMap.get(USER_NAME_PREFIX + userNameByToken);
        if (userSession != null&& userSession.isOpen()) {
            try {
                userSession.sendMessage(new TextMessage("系统通知: " + message));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            // 用户不在线, 可以选择将消息存储在某个地方, 待用户上线后再推送
            System.out.println("用户 " + " 不在线, 无法立即发送通知消息。");
            // 将消息存储在某个地方, 例如 Redis 或数据库
            StringKAndVForm form = new StringKAndVForm();
            form.setKey(RedisKey.merchantApplyNoticeKey(userId));
            form.setValue(message);
            accountOpenFeign.set(form);
        }
    }


    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
        String uri = webSocketSession.getUri().toString();
        String token = uri.substring(uri.lastIndexOf("/") + 1);
        System.out.println("提取到的 token: " + token);
        Integer userIdByToken = myTool.getUserIdByToken(token);
        String userNameByToken = myTool.getUserNameByToken(userIdByToken);
        this.userName = userNameByToken;
        this.session = webSocketSession;
        sessionMap.put(USER_NAME_PREFIX + userName, session);
        webSocketSet.add(this);
            //检查是否有未读消息
        String s = RedisKey.merchantApplyNoticeKey(String.valueOf(userIdByToken));
        Result result = accountOpenFeign.hasKey(s);
        Object data = result.getData();
        if ((Boolean) data) {
            //把消息取出来
            Result string = accountOpenFeign.getString(RedisKey.merchantApplyNoticeKey(String.valueOf(userIdByToken)));
            String message = string.getData().toString();
            //发送消息
            sendNotification(String.valueOf(userIdByToken), message);
            //移除消息
            accountOpenFeign.delete(RedisKey.merchantApplyNoticeKey(String.valueOf(userIdByToken)));
        }

        String tips = userName + " 加入聊天室。当前聊天室人数为" + webSocketSet.size();
        System.out.println(tips);
        // 向当前用户发送通知
        //这个方法会把消息发送给所有在线用户
//        publicMessage(userName, tips, true);

//        // 开启定时任务，定时发送心跳消息
        scheduler.scheduleAtFixedRate(() -> {
            try {
                if (session.isOpen()) {
//                    session.sendMessage(new TextMessage("heartbeat"));
                }
            } catch (Exception e) {
                System.out.println("心跳发送失败，关闭连接：" + session.getId());
                try {
                    session.close();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }, HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL, TimeUnit.MILLISECONDS);
    }

    // 处理消息 处理
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
        if (webSocketMessage instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) webSocketMessage;
            String msg = textMessage.getPayload();

            if (JSONUtil.isTypeJSONObject(msg)) {
                SocketMag socketMsg = JSONUtil.toBean(msg, SocketMag.class);

                if (socketMsg.getType() == 1) {
                    privateMessage(socketMsg);
                } else {
                    publicMessage(socketMsg.getSendOutUser(), socketMsg.getSendOutUser() + ": " + socketMsg.getMsg(), false);
                }
            }
        } else {
            throw new IllegalArgumentException("只接受文本消息");
        }
    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable error) throws Exception {
        System.out.println("userName为：" + userName + "，发生错误：" + error.getMessage());
        error.printStackTrace();
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        if (sessionMap.containsKey(USER_NAME_PREFIX + userName)) {
            sessionMap.remove(USER_NAME_PREFIX + userName);
            webSocketSet.remove(this);
        }
        System.out.println("用户 " + userName + " 已关闭连接，关闭状态：" + closeStatus);
        if (closeStatus.getCode() == CloseStatus.NORMAL.getCode()) {
            System.out.println("连接正常关闭。");
        } else {
            System.out.println("连接异常关闭，状态码：" + closeStatus.getCode());
        }
        String tips = userName + " 退出聊天室。当前聊天室人数为 " + webSocketSet.size();
        System.out.println(tips);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    // 群聊：公开聊天记录
    public synchronized  void publicMessage(String userName, String message, boolean flag) {
        for (WebSocketUtil item : webSocketSet) {
            WebSocketSession session = item.session;
            if (flag) {
                try {
                    session.sendMessage(new TextMessage(message));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                WebSocketSession currentUser = sessionMap.get(USER_NAME_PREFIX + userName);
                if (!session.getId().equals(currentUser.getId())) {
                    try {
                        session.sendMessage(new TextMessage(message));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        System.out.println("公共频道接收了一条消息：" + message);
    }


    // 在WebSocketUtil中添加连接状态监控
    public void checkConnections() {
        Iterator<Map.Entry<String, WebSocketSession>> iterator = sessionMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, WebSocketSession> entry = iterator.next();
            WebSocketSession session = entry.getValue();
            if (!session.isOpen()) {
                iterator.remove();
                webSocketSet.removeIf(util -> util.getSession().getId().equals(session.getId()));
                System.out.println("清理无效连接：" + entry.getKey());
            }
        }
    }
}
